#include "CmdFuncImpForReceiver.h"
#include "../Core/msgbus_interface.h"
#include "../Core/msgbus_handlerbase.hpp"
#include "../Biz/WWBizUtility.h"
#include "utility.hpp"
#include "../Core/xparam.hpp"
#include "../Biz/WWBizCommonDef.h"
#include "../Core/condition.hpp"
#include "../Biz/MsgBusParam/IMContactParam.h"
#include "../Biz/MsgBusParam/IMFileTransferParam.h"
#include "utility_inline.hpp"

#include <string>
#include <termios.h>
#include <unistd.h>
#include <stdio.h>
#include <iostream>
#include <readline/readline.h>
#include <readline/history.h>
using namespace std;
using namespace NetMsgBus;
using namespace wwbiz;

int BuildHelpDetailFunc(const std::string& strargs)
{
    core::XParam allhelp_infos;
    allhelp_infos.put_Str("login", "login aliww use the first argument for the login user name.");
    allhelp_infos.put_Str("sendmsg", "send a message to an user( or many users ).");
    bool ret = allhelp_infos.ToJsonFile(FileUtility::GetWWGlobalCfgPath() + "/command_help.json");

    if(!ret)
    {
        printf("build help detail file failed.\n");
        return -1;
    }
    printf("help detail build success.\n");

    return 0;
}

int HelpFunc(const std::string& strargs)
{
    std::vector<std::string> args;
    FrontEndUtility::split_string(strargs, args, " ");
    assert(args.size() > 0);
    if(args.size() == 1)
    {
        core::XParam allhelp_infos;
        bool ret = allhelp_infos.FromJsonFile(FileUtility::GetWWGlobalCfgPath() + "/command_help.json");

        if(!ret)
        {
            return -1;
        }
        std::string helpdetail;
        allhelp_infos.get_Str(args[0], helpdetail);
        if(!helpdetail.empty())
        {
            printf("\n");
            printf("detail help for %s:\n", args[0].c_str());
            printf("%s\n", helpdetail.c_str());
            printf("\n");
            return 0;
        }
        else
        {
            printf("no more help information for this command.\n");
            return -1;
        }
    }
    printf("wrong argument.\n");
    return -1;
}

int LoginFunc(const std::string& strargs)
{
    std::vector<std::string> args;
    FrontEndUtility::split_string(strargs, args, " ");
    std::string userid;
    std::string pass;
//    IMPREDEFSTATUS_FREE	= 1,
//    IMPREDEFSTATUS_BUSY	= 2,
//    IMPREDEFSTATUS_AWAY	= 3,
//    IMPREDEFSTATUS_INCALL	= 4,
//    IMPREDEFSTATUS_OUTFORDINNER	= 5,
//    IMPREDEFSTATUS_WAIT	= 6,
//    IMPREDEFSTATUS_INVISIBLE	= 7,
    int loginstate = 7;
    if(args.size() > 2)
    {
        printf("too many args.\n");
        return -1;
    }
    if(args.size() == 2)
    {
        if(args[1] == "free")
            loginstate = 1;
        else if(args[1] == "invisible")
            loginstate = 7;
        else
        {
            printf("unknown state , use invisible as default.\n");
        }
    }
    if(args.size() >= 1)
        userid = args[0];
    else
    {
        std::cout << "input login id: (only support taobao user.)" << std::endl;
        std::cin >> userid;
    }
    FrontEndUtility::set_noecho(true);
    char * tmpbuffer;
    tmpbuffer = readline("input password:");
    if(tmpbuffer == NULL)
    {
        perror("read command error");
        return -1;
    }
    pass = string(tmpbuffer); 
    free(tmpbuffer);
    FrontEndUtility::set_noecho(false);

    cout << "start login ..." << endl;

    FrontEndUtilityInline::SimpleEncode(pass, pass, userid);
    core::XParam xp;
    xp.put_Str("userid", userid);
    xp.put_Str("pass", pass);
    xp.put_Int("loginstate", loginstate);
    NetMsgBus::PostMsg("im.frontend.cmd.dologin", CustomType2Param(xp));

    pass.clear();
    return 0;
}

int ReLoginFunc(const std::string& strargs)
{
    int loginstate = 1;
    core::XParam xp;
    xp.put_Int("loginstate", loginstate);
    NetMsgBus::PostMsg("im.frontend.cmd.dorelogin", CustomType2Param(xp));
    printf("note: relogin only available while you are disconnect for net error or kicked by server\n");
    return 0;
}

int LogoutFunc(const std::string& strargs)
{
    NetMsgBus::PostMsg("im.frontend.cmd.dologout");
    return 0;
}
class VerifyInfoHandler : public MsgHandler<VerifyInfoHandler>
{
public:
    VerifyInfoHandler()
    {
    }
    void InitMsgHandler()
    {
        AddHandler("im.frontend.cmd.userverifyinfo.update", &VerifyInfoHandler::OnVerifyUpdate, 0);
    }
    int WaitVerify(const std::string& name, std::string& matchuid, int type = VERIFYTYPE_CHECKSENDMSG)
    {
        core::XParam vinfo;
        vinfo.put_Str("verifyname", name);
        vinfo.put_Int("verifytype", type);
        MsgBusParam msgparam = CustomType2Param(vinfo);
        NetMsgBus::SendMsg("im.frontend.cmd.doverifyuser", msgparam);
        struct timespec ts;
        ts.tv_sec = time(NULL) + 4;
        ts.tv_nsec = 0;
        bool ready = false;
        while(!ready)
        {
            core::common::locker_guard guard(m_locker);
            int retcode = m_cond.waittime(m_locker, &ts);
            if(retcode == ETIMEDOUT)
                return -1;
            ready = (m_verifyinfo.m_uid == name || m_verifyinfo.m_dispname == name);
        }
        int flag = m_verifyinfo.m_verifyflag;
        matchuid = m_verifyinfo.m_uid;
        return flag;
    }

    bool OnVerifyUpdate(const std::string& msgid, MsgBusParam& param, bool& is_continue)
    {
        Param2CustomType(param, m_verifyinfo);
        m_cond.notify_one();
        return true;
    }
private:
    IMUserVerifyInfo  m_verifyinfo;
    core::common::locker  m_locker;
    core::common::condition m_cond;
};

int SendMsgFunc(const std::string& strargs)
{
    std::vector<std::string> args;
    FrontEndUtility::split_string(strargs, args, " ");
    if(args.size() != 1)
    {
        printf("wrong argument!(dest userid needed.)\n");
        return -1;
    }
    boost::shared_ptr<VerifyInfoHandler> vhandler(new VerifyInfoHandler());
    vhandler->InitMsgHandler();
    std::string senduid;
    int ret = vhandler->WaitVerify(args[0], senduid);
    if(ret == -1)
    {
        printf("request to server to verify the user timeout.\n");
        return -1;
    }

    if(ret != ADDEDAUTH_NONE)
    {
        if(ret == ADDEDAUTH_NOUID)
        {
            printf("the user does not exist.\n");
        }
        else
        {
            printf("the user don't allow you to send message to him, you should add the user as friend first.\n");
        }
        return -1;
    }
    std::vector<std::string> matchuids;
    matchuids.push_back(senduid);
    int selected = 1;
    if(matchuids.size() > 1)
    {
        printf("the name you input matches more than one user, select one (0 for all):\n");
        for(size_t i = 0; i < matchuids.size(); i++)
        {
            printf("\t%zu. %s", i + 1, matchuids[i].c_str());
        }
        printf("\n");
        cin >> selected;
        while(selected > (int)matchuids.size() || selected < 0)
        {
            if(selected == -1)
            {
                printf("send message aborted.\n");
                return 0;
            }
            printf("wrong input! please reinput.(-1 abort send.)\n");
            cin >> selected;
        }
        cin.ignore(1, '\n');
    }
    if(selected < 0 || selected > (int)matchuids.size())
    {
        printf("wrong input. send aborted.\n");
        return -1;
    }
    cout << "please input essage content, end input by ##." << endl;
    string content;
    string line;
    getline(cin, line);
    while(line != "##")
    {
        content += line;
        getline(cin, line);
    }
    if(content.empty())
    {
        printf("empty content not allowed.\n");
        return -1;
    }
    if(selected > 0)
    {
        core::XParam sendmsginfo;
        sendmsginfo.put_Str("uid", matchuids[selected - 1]);
        sendmsginfo.put_Str("content", content);
        NetMsgBus::PostMsg("im.frontend.cmd.dosendtextmsg", CustomType2Param(sendmsginfo));
    }
    else
    {
        // multisend.
        printf("multisend not supported yet.\n");
    }
    return 0;
}

int SendFileFunc(const std::string& strargs)
{
    std::vector<std::string> args;
    FrontEndUtility::split_string(strargs, args, " ");
    if(args.size() < 1)
    {
        printf("wrong argument!(dest userid needed.)\n");
        return -1;
    }
    boost::shared_ptr<VerifyInfoHandler> vhandler(new VerifyInfoHandler());
    vhandler->InitMsgHandler();
    std::string senduid;
    int ret = vhandler->WaitVerify(args[0], senduid);
    if(ret == -1)
    {
        printf("request to server to verify the user timeout.\n");
        return -1;
    }

    if(ret != ADDEDAUTH_NONE)
    {
        if(ret == ADDEDAUTH_NOUID)
        {
            printf("the user does not exist.\n");
        }
        else
        {
            printf("the user don't allow you to send file to him, you should add the user as friend first.\n");
        }
        return -1;
    }
    std::vector<std::string> matchuids;
    matchuids.push_back(senduid);
    int selected = 1;
    if(matchuids.size() > 1)
    {
        printf("the name you input matches more than one user, select one (0 for all):\n");
        for(size_t i = 0; i < matchuids.size(); i++)
        {
            printf("\t%zu. %s", i + 1, matchuids[i].c_str());
        }
        printf("\n");
        cin >> selected;
        while(selected > (int)matchuids.size() || selected < 0)
        {
            if(selected == -1)
            {
                printf("send aborted.\n");
                return 0;
            }
            printf("wrong input! please reinput.(-1 abort send.)\n");
            cin >> selected;
        }
        cin.ignore(1, '\n');
    }
    if(selected < 0 || selected > (int)matchuids.size())
    {
        printf("wrong input. send aborted.\n");
        return -1;
    }
    string line;
    if(args.size() < 2)
    {
        cout << "please input file full path name you want to send." << endl;
        getline(cin, line);
        if(line.empty())
        {
            printf("empty filename not allowed.\n");
            return -1;
        }
    }
    else
    {
        line = args[1];
    }
    if(selected > 0)
    {
        core::XParam sendfileinfo;
        sendfileinfo.put_Str("uid", matchuids[selected - 1]);
        sendfileinfo.put_Str("filename", line);
        NetMsgBus::PostMsg("im.frontend.cmd.dosendfile", CustomType2Param(sendfileinfo));
    }
    else
    {
        // multisend.
        printf("multisend not supported yet.\n");
    }
    return 0;

}

int ExportBinMsgsFunc(const std::string& strargs)
{
    std::vector<std::string> args;
    FrontEndUtility::split_string(strargs, args, " ");
    if(args.size() != 1)
    {
        printf("please input the export file path.\n");
        return -1;
    }
    core::XParam exportxp;
    exportxp.put_Str("exportpath", args[0]);

    NetMsgBus::PostMsg("im.frontend.cmd.doexportbinmsgs", CustomType2Param(exportxp));
    return 0;
}

int RecvFileFunc(const std::string& strargs)
{
    std::vector<std::string> args;
    FrontEndUtility::split_string(strargs, args, " ");
    if(args.size() < 1)
    {
        printf("not enough argument.\n");
        return -1;
    }
    FileTransferNotify notify;
    notify.session = args[0];
    notify.notifytype = "accept";
    if(args.size() > 1)
    {
        notify.recvpath = args[1];
    }
    else
    {
        printf("no receive path specified, use default path.  \n");
    }

    NetMsgBus::PostMsg("im.frontend.cmd.filetransfer.donotifyotherside", CustomType2Param(notify));
    return 0;
}

int RejectFileFunc(const std::string& strargs)
{
    std::vector<std::string> args;
    FrontEndUtility::split_string(strargs, args, " ");
    if(args.size() < 1)
    {
        printf("not enough argument.\n");
        return -1;
    }
    FileTransferNotify notify;
    notify.session = args[0];
    notify.notifytype = "reject";
    NetMsgBus::PostMsg("im.frontend.cmd.filetransfer.donotifyotherside", CustomType2Param(notify));
    return 0;
}

int InfoFunc(const std::string& strargs)
{
    return 0;
}

int QuitFunc(const std::string& strargs)
{
    NetMsgBus::SendMsg("im.frontend.cmd.doquit");
    return 0;
}
